package com.example.appointment.service.impl;

import com.example.appointment.dto.HealthCheckDTO;
import com.example.appointment.dto.HealthCheckStatsDTO;
import com.example.appointment.entity.HealthCheck;
import com.example.appointment.entity.User;
import com.example.appointment.exception.ResourceNotFoundException;
import com.example.appointment.repository.HealthCheckRepository;
import com.example.appointment.repository.UserRepository;
import com.example.appointment.service.HealthCheckService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
public class HealthCheckServiceImpl implements HealthCheckService {
    
    private final HealthCheckRepository healthCheckRepository;
    private final UserRepository userRepository;
    
    public HealthCheckServiceImpl(HealthCheckRepository healthCheckRepository, UserRepository userRepository) {
        this.healthCheckRepository = healthCheckRepository;
        this.userRepository = userRepository;
    }
    
    @Override
    @Transactional
    public HealthCheckDTO createHealthCheck(HealthCheckDTO healthCheckDTO) {
        log.info("开始创建健康打卡记录，用户ID: {}", healthCheckDTO.getUserId());
        
        if (healthCheckDTO.getUserId() == null) {
            log.error("用户ID为空");
            throw new IllegalArgumentException("User ID cannot be null");
        }
        
        // 先检查用户是否存在，并打印详细信息
        boolean userExists = userRepository.existsById(healthCheckDTO.getUserId());
        log.info("用户ID {} 是否存在于数据库: {}", healthCheckDTO.getUserId(), userExists);
        
        User user = userRepository.findById(healthCheckDTO.getUserId())
                .orElseThrow(() -> {
                    log.error("用户ID: {} 不存在", healthCheckDTO.getUserId());
                    return new ResourceNotFoundException("User", "id", healthCheckDTO.getUserId());
                });
        
        log.info("找到用户: {}, ID: {}, 角色: {}", user.getUsername(), user.getId(), user.getRole());
        
        HealthCheck healthCheck = new HealthCheck();
        healthCheck.setUser(user);
        healthCheck.setType(healthCheckDTO.getType());
        healthCheck.setContent(healthCheckDTO.getContent());
        healthCheck.setDuration(healthCheckDTO.getDuration());
        healthCheck.setMood(healthCheckDTO.getMood());
        
        try {
            HealthCheck savedHealthCheck = healthCheckRepository.save(healthCheck);
            log.info("健康打卡记录创建成功，ID: {}", savedHealthCheck.getId());
            return convertToDTO(savedHealthCheck);
        } catch (Exception e) {
            log.error("保存健康打卡记录失败: {}", e.getMessage(), e);
            throw e;
        }
    }
    
    @Override
    public HealthCheckDTO getHealthCheck(Long id) {
        HealthCheck healthCheck = healthCheckRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Health check not found with id: " + id));
        return convertToDTO(healthCheck);
    }
    
    @Override
    public Page<HealthCheckDTO> getHealthChecks(Long userId, String type, LocalDate startDate, LocalDate endDate, Pageable pageable) {
        Page<HealthCheck> healthChecks;
        
        if (type != null && !type.isEmpty() && startDate != null && endDate != null) {
            LocalDateTime startDateTime = startDate.atStartOfDay();
            LocalDateTime endDateTime = endDate.atTime(LocalTime.MAX);
            healthChecks = healthCheckRepository.findByUserIdAndTypeAndCreateTimeBetween(userId, type, startDateTime, endDateTime, pageable);
        } else if (type != null && !type.isEmpty()) {
            healthChecks = healthCheckRepository.findByUserIdAndType(userId, type, pageable);
        } else if (startDate != null && endDate != null) {
            LocalDateTime startDateTime = startDate.atStartOfDay();
            LocalDateTime endDateTime = endDate.atTime(LocalTime.MAX);
            healthChecks = healthCheckRepository.findByUserIdAndCreateTimeBetween(userId, startDateTime, endDateTime, pageable);
        } else {
            healthChecks = healthCheckRepository.findByUserId(userId, pageable);
        }
        
        return healthChecks.map(this::convertToDTO);
    }
    
    @Override
    @Transactional
    public HealthCheckDTO updateHealthCheck(Long id, HealthCheckDTO healthCheckDTO) {
        HealthCheck healthCheck = healthCheckRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Health check not found with id: " + id));
        
        // 确保只能更新自己的打卡记录
        if (!Objects.equals(healthCheck.getUser().getId(), healthCheckDTO.getUserId())) {
            throw new IllegalArgumentException("You can only update your own health check records");
        }
        
        healthCheck.setType(healthCheckDTO.getType());
        healthCheck.setContent(healthCheckDTO.getContent());
        healthCheck.setDuration(healthCheckDTO.getDuration());
        healthCheck.setMood(healthCheckDTO.getMood());
        
        HealthCheck updatedHealthCheck = healthCheckRepository.save(healthCheck);
        return convertToDTO(updatedHealthCheck);
    }
    
    @Override
    @Transactional
    public void deleteHealthCheck(Long id) {
        if (!healthCheckRepository.existsById(id)) {
            throw new ResourceNotFoundException("Health check not found with id: " + id);
        }
        healthCheckRepository.deleteById(id);
    }
    
    @Override
    public HealthCheckStatsDTO getHealthCheckStats(Long userId, String timeRange) {
        HealthCheckStatsDTO stats = new HealthCheckStatsDTO();
        
        // 获取总打卡次数
        stats.setTotalCheckins(healthCheckRepository.countByUserId(userId));
        
        // 基于时间范围计算
        LocalDateTime startDate;
        LocalDateTime now = LocalDateTime.now();
        
        if ("7days".equals(timeRange)) {
            startDate = now.minusDays(7);
        } else if ("30days".equals(timeRange)) {
            startDate = now.minusDays(30);
        } else {
            // 默认获取所有记录的统计信息
            startDate = LocalDateTime.of(2000, 1, 1, 0, 0); // 一个较早的日期
        }
        
        // 获取本周打卡次数
        LocalDateTime weekStart = now.with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY)).withHour(0).withMinute(0).withSecond(0);
        stats.setThisWeekCount(healthCheckRepository.countByUserIdAndCreateTimeAfter(userId, weekStart));
        
        // 获取本月打卡次数
        LocalDateTime monthStart = now.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0);
        stats.setThisMonthCount(healthCheckRepository.countByUserIdAndCreateTimeAfter(userId, monthStart));
        
        // 获取连续打卡天数
        Integer continuousDays = healthCheckRepository.getContinuousDays(userId, startDate);
        stats.setContinuousDays(continuousDays != null ? continuousDays : 0);
        
        // 添加图表数据
        generateFrequencyData(stats, userId, startDate);
        generateTypeDistribution(stats, userId, startDate);
        generateMoodData(stats, userId, startDate);
        
        return stats;
    }
    
    /**
     * 生成打卡频率数据
     */
    private void generateFrequencyData(HealthCheckStatsDTO stats, Long userId, LocalDateTime startDate) {
        try {
            // 获取过去7天的日期
            LocalDate today = LocalDate.now();
            List<Map<String, Object>> frequencyData = new ArrayList<>();
            
            for (int i = 6; i >= 0; i--) {
                LocalDate date = today.minusDays(i);
                LocalDateTime dayStart = date.atStartOfDay();
                LocalDateTime dayEnd = date.atTime(23, 59, 59);
                
                // 查询当天的打卡次数
                Long count = healthCheckRepository.countByUserIdAndCreateTimeBetween(userId, dayStart, dayEnd);
                
                Map<String, Object> dayData = new HashMap<>();
                dayData.put("date", date.toString());
                dayData.put("count", count);
                
                frequencyData.add(dayData);
            }
            
            stats.setFrequencyData(frequencyData);
        } catch (Exception e) {
            log.error("生成打卡频率数据失败", e);
            // 创建空数据防止前端报错
            stats.setFrequencyData(new ArrayList<>());
        }
    }
    
    /**
     * 生成打卡类型分布数据
     */
    private void generateTypeDistribution(HealthCheckStatsDTO stats, Long userId, LocalDateTime startDate) {
        try {
            // 查询不同类型的打卡数量
            Map<String, Long> typeCounts = healthCheckRepository.findByUserIdAndCreateTimeAfter(userId, startDate)
                .stream()
                .collect(Collectors.groupingBy(HealthCheck::getType, Collectors.counting()));
            
            List<Map<String, Object>> typeData = new ArrayList<>();
            
            // 将类型数据转换为前端需要的格式
            for (Map.Entry<String, Long> entry : typeCounts.entrySet()) {
                Map<String, Object> typeItem = new HashMap<>();
                typeItem.put("name", getTypeName(entry.getKey()));
                typeItem.put("value", entry.getValue());
                typeData.add(typeItem);
            }
            
            stats.setTypeDistribution(typeData);
        } catch (Exception e) {
            log.error("生成打卡类型分布数据失败", e);
            stats.setTypeDistribution(new ArrayList<>());
        }
    }
    
    /**
     * 生成心情数据
     */
    private void generateMoodData(HealthCheckStatsDTO stats, Long userId, LocalDateTime startDate) {
        try {
            // 获取过去7天的日期
            LocalDate today = LocalDate.now();
            List<Map<String, Object>> moodData = new ArrayList<>();
            
            for (int i = 6; i >= 0; i--) {
                LocalDate date = today.minusDays(i);
                LocalDateTime dayStart = date.atStartOfDay();
                LocalDateTime dayEnd = date.atTime(23, 59, 59);
                
                // 查询当天的平均心情值
                List<HealthCheck> checksOfDay = healthCheckRepository.findByUserIdAndCreateTimeBetween(userId, dayStart, dayEnd);
                
                double avgMood = 0;
                if (!checksOfDay.isEmpty()) {
                    avgMood = checksOfDay.stream()
                        .mapToInt(HealthCheck::getMood)
                        .average()
                        .orElse(0);
                }
                
                Map<String, Object> dayMood = new HashMap<>();
                dayMood.put("date", date.toString());
                dayMood.put("mood", avgMood);
                
                moodData.add(dayMood);
            }
            
            stats.setMoodData(moodData);
        } catch (Exception e) {
            log.error("生成心情数据失败", e);
            stats.setMoodData(new ArrayList<>());
        }
    }
    
    /**
     * 获取类型名称
     */
    private String getTypeName(String type) {
        switch (type) {
            case "exercise":
                return "运动";
            case "sleep":
                return "睡眠";
            case "diet":
                return "饮食";
            case "other":
                return "其他";
            default:
                return type;
        }
    }
    
    private HealthCheckDTO convertToDTO(HealthCheck healthCheck) {
        HealthCheckDTO dto = new HealthCheckDTO();
        dto.setId(healthCheck.getId());
        dto.setUserId(healthCheck.getUser().getId());
        dto.setType(healthCheck.getType());
        dto.setContent(healthCheck.getContent());
        dto.setDuration(healthCheck.getDuration());
        dto.setMood(healthCheck.getMood());
        dto.setCreateTime(healthCheck.getCreateTime());
        dto.setUpdateTime(healthCheck.getUpdateTime());
        return dto;
    }
} 